using System.Runtime.CompilerServices;
using KinonekoSoftware.CodariaDB.Documents.Composes;
using KinonekoSoftware.CodariaDB.Documents.Timelines;
using KinonekoSoftware.Studio.ViewModels;

namespace KinonekoSoftware.Studio.Pages.Notions
{
    partial class PlotsQuickEditorViewModel
    {
        private bool       _hasStoryPoint;
        private StoryPoint _storyPoint;
        private StoryPoint _uncategorizedStoryPoint;

        //-------------------------------------------------------------
        //
        //          Private Methods
        //
        //-------------------------------------------------------------
        
        
        private void RefreshStoryPointState()
        {

            //
            // 判断是否存在剧情点。
            HasStoryPoint = StoryPointCollection.Count > 0;
        }


        /// <summary>
        /// 新建一个<see cref="CodariaDB.Documents.Timelines.StoryPoint"/> ，并负责将 <see cref="CodariaDB.Documents.Timelines.StoryPoint"/> 添加到数据库、UI以及集合当中。
        /// </summary>
        /// <param name="name"><see cref="CodariaDB.Documents.Timelines.StoryPoint"/> 的名字。</param>
        /// <param name="intro"><see cref="CodariaDB.Documents.Timelines.StoryPoint"/> 的简介。</param>
        /// <returns>返回新建的<see cref="CodariaDB.Documents.Timelines.StoryPoint"/>。</returns>
        private StoryPoint NewStoryPoint(string name, string intro = null)
        {
            var index = StoryPointCollection.Count;
            var point = new StoryPoint
            {
                Id       = ID.GetShortID(),
                Name     = name,
                Intro    = intro,
                Index    = index,
                ParentID = Layer?.Id,
            };
            
            //
            //
            return point;
        }
        
        private void AttachedThisStoryPoint(StoryPoint point)
        {
            _timelineSystem.Attach(point);
        }

        private void AttachedThisPlots(Plot plot)
        {
            _timelineSystem.Attach(plot);
        }
        
        //-------------------------------------------------------------
        //
        //          Command Handlers
        //
        //-------------------------------------------------------------

        private async void DoAddStoryPointCommand()
        {
            if (Plot is null)
            {
                return;
            }

            var r = await MasterDetailViewModel.New(TitleSR.New, "新建一个新的剧情碎片集合。");

            if (!r.IsFinished)
            {
                return;
            }

            //
            // 完成新建
            var point = NewStoryPoint(r.Value.Name, r.Value.Intro);
            
            _timelineSystem.Add(point);

            //
            //
            SetDirtyState(true);
            RefreshStoryPointState();
        }


        private async void DoEditStoryPointCommand(StoryPoint point)
        {

        }

        private void DoRefineStoryPointCommand(StoryPoint point)
        {
            if (point is null)
            {
                return;
            }

            var context = new PageContext
            {
                Id = Plot.Id,
            };

            //
            //
            context.Set(ContextBase.Key_Value, point);

            //
            // 跳转到。
            GoTo<PlotEditorViewModel>(context);
        }
        
        private async void DoAttachStoryPointCommand(StoryPoint point)
        {
            //
            // 合并
            if (point is null)
            {
                var result = await ObjectSelectorViewModel.Single(PlotCollection, instance => ((Plot)instance).Name);

                if (result .IsFinished)
                {
                    return;
                }
                
                AttachedThisPlots(result.Value);
            }
            else
            {
                AttachedThisStoryPoint(point);
            }

            RefreshStoryPointState();
        }


        private async void DoDetachStoryPointCommand(StoryPoint point)
        {
            //
            // 剥离
            if (point is null)
            {
                return;
            }

            TripleSelection selection;


            if (_timelineSystem.IsStoryPointHasChildren(point))
            {
                selection = await Question("剥离当前节点放入灵感池。", "仅剥离当前节点", "剥离当前节点与子节点");
            }
            else
            {
                selection = TripleSelection.Option1;
            }

            if (selection is TripleSelection.Cancel or TripleSelection.Failed)
            {
                return;
            }
            

            if (selection == TripleSelection.Option1)
            {
                _timelineSystem.DetachAsStoryPoint(point);
            }
            else
            {
                _timelineSystem.DetachAsPlot(point);
            }
            
            //
            // 判断当前层次的故事点是否为删除的故事点。
            if (ReferenceEquals(Layer, point))
            {
                Layer = StoryPointCollection.FirstOrDefault();
                _timelineSystem.PushStoryPointLayer(Layer);
            }

            //
            //
            DetachedStoryPoint = point;

            //
            //
            SetDirtyState(true);
            RefreshLayerIndicatorState();
            RefreshStoryPointState();
        }


        private void DoShiftUpStoryPointCommand(StoryPoint point)
        {
            if (point is null)
            {
                return;
            }

            _timelineSystem.ShiftUp(point);
        }


        private void DoShiftDownStoryPointCommand(StoryPoint point)
        {
            if (point is null)
            {
                return;
            }


            _timelineSystem.ShiftDown(point);
        }


        private async void DoRemoveStoryPointCommand(StoryPoint point)
        {
            if (point is null)
            {
                return;
            }

            TripleSelection selection;

            //
            // algorithm complexity: O(N)
            // 判断是否有子节点。
            if (_timelineSystem.IsStoryPointHasChildren(point))
            {
                //
                // 如果存在子节点，则询问是仅删除节点还是所有。
                selection = await Question("当前节点中有子节点，请问是否要继续删除?", "仅删除本节点", "删除当前节点和子节点");
            }
            else
            {
                //
                // 没有子节点的情况，用仅删除节点选项或者取消选项替代。
                selection = await RemoveItem() ? TripleSelection.Option1 : TripleSelection.Cancel;
            }

            if (selection == TripleSelection.Cancel)
            {
                return;
            }


            if (selection == TripleSelection.Option1)
            {
                //
                // 仅删除当前节点
                _timelineSystem.Remove(point);
            }
            else
            {
                //
                // O(N)，获得所有子元素。
                _timelineSystem.RemoveSubTree(point);
            }
            
            //
            // 判断当前选择的故事点是否为删除的故事点。
            if (ReferenceEquals(StoryPoint, point))
            {
                //
                // 在同级里面随便选一个上来顶着。
                StoryPoint = StoryPointCollection.FirstOrDefault();
            }

            //
            // 判断当前层次的故事点是否为删除的故事点。
            if (ReferenceEquals(Layer, point))
            {
                _timelineSystem.PushStoryPointLayer(point);
            }

            //
            // 标记为已更改。
            SetDirtyState(true);
            RefreshStoryPointState();
        }

        //-------------------------------------------------------------
        //
        //          Properties
        //
        //-------------------------------------------------------------

        public ObservableList<StoryPoint>       StoryPointCollection         => _timelineSystem.StoryPointCollection;
        public ObservableCollection<StoryPoint> StoryPointLayerList          => _timelineSystem.StoryPointLayerList;
        public ObservableCollection<StoryPoint> DetachedStoryPointCollection => _timelineSystem.DetachedStoryPointCollection;


        public StoryPoint StoryPoint
        {
            get => _storyPoint;
            set
            {
                SetValue(ref _storyPoint, value);
                _timelineSystem.StoryPoint = value;
            }
        }


        public StoryPoint DetachedStoryPoint
        {
            get => _uncategorizedStoryPoint;
            set
            {
                SetValue(ref _uncategorizedStoryPoint, value);
            }
        }

        public bool HasStoryPoint
        {
            get => _hasStoryPoint;
            private set => SetValue(ref _hasStoryPoint, value);
        }

        //-------------------------------------------------------------
        //
        //          Commands
        //
        //-------------------------------------------------------------

        public ICommandEX AddStoryPointCommand       { get; }
        public ICommandEX EditStoryPointCommand      { get; }
        public ICommandEX RefineStoryPointCommand    { get; }
        public ICommandEX AttachStoryPointCommand    { get; }
        public ICommandEX DetachStoryPointCommand    { get; }
        public ICommandEX ShiftUpStoryPointCommand   { get; }
        public ICommandEX ShiftDownStoryPointCommand { get; }
        public ICommandEX RemoveStoryPointCommand    { get; }
    }
}